#include "app_power.h"

#define APP_DC_PORT                 GPIOA
#define APP_BAT_PORT                GPIOA
#define APP_DC_PIN                  LL_GPIO_PIN_7
#define APP_BAT_PIN                 LL_GPIO_PIN_6
#define APP_DC_PIN_ReadLevel()      LL_GPIO_IsInputPinSet(APP_DC_PORT, APP_DC_PIN)
#define BAT_ADC_INTERVAL            (10 * 1000) // (60 * 1000) // 电池供电情况下 每分钟检测一次电量
#define DC_ADC_INTERVAL             (10 * 1000) // DC供电情况下 每10秒检测一次电量

#define BAT_LOW_THRESHOLD           2358    // ((3.8v / 2) * 4096) / 3.3v
#define BAT_OFF_THRESHOLD           2265    // ((3.65v / 2) * 4096) / 3.3v
#define BAT_NOT_INSTALLED_THRESHOLD 1000    // 电池未安装

void app_power_init(void)
{
    LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);

    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
    LL_EXTI_InitTypeDef EXTI_InitStruct = {0};

    GPIO_InitStruct.Pin     = APP_DC_PIN; 
    GPIO_InitStruct.Mode    = LL_GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull    = LL_GPIO_PULL_NO;
    LL_GPIO_Init(APP_DC_PORT, &GPIO_InitStruct);

    /* Configure EXTI as interrupt, falling edge triggered */
    EXTI_InitStruct.Line        = LL_EXTI_LINE_7;
    EXTI_InitStruct.LineCommand = ENABLE;
    EXTI_InitStruct.Mode        = LL_EXTI_MODE_IT_EVENT;
    EXTI_InitStruct.Trigger     = LL_EXTI_TRIGGER_RISING_FALLING;
    LL_EXTI_Init(&EXTI_InitStruct);

    /* When using EXTI channels 0~8, configure the trigger port, for example:*/
    LL_EXTI_SetEXTISource(LL_EXTI_CONFIG_PORTA, LL_EXTI_CONFIG_LINE7);
    
    /* Enable interrupt */
    NVIC_SetPriority(EXTI4_15_IRQn, 5);
    NVIC_EnableIRQ(EXTI4_15_IRQn);

    if (RESET == APP_DC_PIN_ReadLevel()) {
        dev_obj->type = BAT_TYPE;
    } else {
        dev_obj->type = DC_TYPE;
    }
    dev_obj->battery = 0xFFFF;
}


// void app_power_irq_handler(void)
// {
//     if (RESET == APP_DC_PIN_ReadLevel()) {
//         dev_obj->type = BAT_TYPE;
//     } else {
//         dev_obj->type   = DC_TYPE;
//         dev_obj->power  = POWER_OK;
//     }
// }

static unsigned char app_power_percent(int value)
{
    const int max_val = 2792;
    const int min_val = 2265;

    if (value > max_val) {
        value = max_val;
    } else if (value < min_val) {
        value = min_val;
    }

    int range = max_val - min_val;
    int percent = ((value - min_val) * 100) / range;

    return (unsigned char)(percent & 0xFF);
}


static void app_power_battery_level_read(void)
{
    static unsigned int last_time = 0x00;
    unsigned int interval = dev_obj->type == DC_TYPE ? DC_ADC_INTERVAL : BAT_ADC_INTERVAL;
    interval = last_time == 0 ? 0 : last_time;

    if (time_after(app_sys_ticks, last_time + interval) && app_release_is_finished()) {
        last_time = app_sys_ticks;
        dev_obj->battery = app_adc_convert(LL_ADC_CHANNEL_5);
    }
}

static void app_power_state_change(unsigned char state)
{
    if (dev_obj->type == DC_TYPE) {
        dev_obj->power = POWER_OK;
    } else {
        dev_obj->power = state;
    }
}

static void app_power_battery_low_handler(void)
{
    if (dev_obj->battery <= BAT_LOW_THRESHOLD && dev_obj->battery > BAT_OFF_THRESHOLD) {
        if ((dp_obj->fault & (1 << BAT_LOW)) == 0) {
            dp_obj->fault |= (1 << BAT_LOW);
            app_dp_fault_notify();
        }

        if (dev_obj->power == POWER_OK) {
            app_led_toggle(APP_LED_BAT, APP_TOGGLE_SLOW_TIME, 0x00);
            app_power_state_change(POWER_LOW);
        }
    } else if (dev_obj->battery <= BAT_OFF_THRESHOLD && dev_obj->battery > BAT_NOT_INSTALLED_THRESHOLD) {
        if ((dp_obj->fault & (1 << BAT_LOW)) == 0) {
            dp_obj->fault |= (1 << BAT_LOW);
            app_dp_fault_notify();
        }
        // 电池关机
        app_power_state_change(POWER_OFF);
    } else {
        if (dev_obj->power == POWER_OFF && dev_obj->battery > BAT_LOW_THRESHOLD) {
            app_power_state_change(POWER_LOW);
        }

        if (dev_obj->power == POWER_LOW && dev_obj->battery > BAT_LOW_THRESHOLD + 100) {
            app_power_state_change(POWER_OK);
            if (dp_obj->fault & (1 << BAT_LOW)) {
                dp_obj->fault &= ~(1 << BAT_LOW);
                app_dp_fault_notify();
            }
        }
    }
}

static void app_power_battery_level_handler(void)
{
    if (dev_obj->type == BAT_TYPE) {
        if (dev_obj->battery <= BAT_LOW_POWER_ALARM_PERCENT && dev_obj->battery > BAT_LOW_POWER_OFF_PERCENT) {
            if ((dp_obj->fault & (1 << BAT_LOW)) == 0) {
                dp_obj->fault |= (1 << BAT_LOW);
                app_dp_fault_notify();
            }

            // 低电量
            if (dev_obj->power == POWER_OK) {
                dev_obj->power = POWER_LOW;
            }
        } else if (dev_obj->battery <= BAT_LOW_POWER_OFF_PERCENT) {
            dev_obj->power = POWER_OFF;
        } else {
            if (dev_obj->power == POWER_OFF && dev_obj->battery > BAT_LOW_POWER_ALARM_PERCENT) {
                dev_obj->power = POWER_LOW;
            } else if (dev_obj->power == POWER_LOW && dev_obj->battery > BAT_LOW_POWER_ALARM_PERCENT + 7) {
                dev_obj->power = POWER_OK;
                if (dp_obj->fault & (1 << BAT_LOW)) {
                    dp_obj->fault &= ~(1 << BAT_LOW);
                    app_dp_fault_notify();
                }
            }
        }
    } else {
        dev_obj->power = POWER_OK;
    }
}

void app_power_task(void)
{
    app_power_battery_level_read();
    app_power_battery_low_handler();
}

unsigned char app_power_is_battery(void)
{
    if (SET == APP_DC_PIN_ReadLevel()) {
        return 0x00;
    }

    return 0x01;
}

unsigned char app_power_is_low_level(void)
{
    // if (dev_obj->power == POWER_LOW || dev_obj->power == POWER_OFF) {
    if (dev_obj->power == POWER_OFF) {
        return 0x01;
    }

    return 0x00;
}

unsigned char app_power_is_off(void)
{
    if (dev_obj->power == POWER_OFF) {
        return 0x01;
    }

    return 0x00;
}